/**
 * Copyright 2007 Tony Stubblebine
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @fileoverview This file implements a rails container. It's a work in
 * progress and so starts with the Google in-memory container so that we can
 * always have a working container while building the rails functionality.
 */

/**
 * Implements the opensocial.Container apis.
 *
 * @param {Person} viewer Person object that corresponds to the viewer.
 * @param {Person} opt_owner Person object that corresponds to the owner.
 * @param {Collection&lt;Person&gt;} opt_viewerFriends A collection of the
 *    viewer's friends
 * @param {Collection&lt;Person&gt;} opt_ownerFriends A collection of the
 *    owner's friends
 * @param {Map&lt;String, String&gt;} opt_globalAppData map from key to value
 *    of the global app data
 * @param {Map&lt;String, String&gt;} opt_instanceAppData map from key to value
 *    of this gadget's instance data
 * @param {Map&lt;Person, Map&lt;String, String&gt;&gt;} opt_personAppData map
 *    from person to a map of app data key value pairs.
 * @param {Map&lt;String, Array&lt;Activity&gt;&gt;} opt_activities A map of
 *    person ids to the activities they have.
 * @constructor
 */
opensocial.RailsContainer = function(viewer,
    opt_owner, opt_viewerFriends, opt_ownerFriends, opt_globalAppData,
    opt_instanceAppData, opt_personAppData, opt_activities, opt_appId) {
  this.viewer = viewer;
  this.owner = opt_owner;
  this.viewerFriends = opt_viewerFriends || {};
  this.ownerFriends = opt_ownerFriends || {};
  this.globalAppData = opt_globalAppData || {};
  this.instanceAppData = opt_instanceAppData || {};
  this.personAppData = opt_personAppData || {};
  this.activities = opt_activities || {};
  this.appId = opt_appId || 'sampleContainerAppId';
};
opensocial.RailsContainer.inherits(opensocial.MockContainer);

/** callback for handling an ajax call to retrieve a person */
opensocial.RailsContainer.prototype.onFetchPerson = function(xml, request, callback, requestName, isViewer, isOwner) {
  var globalError = false;
  var dataResponseValues = [];
  var fields = {
    'id' : $(xml).find('id').text(),
    'name' : $(xml).find('title').text()
  };
  if ($("link[rel=thumbnail]", xml)) {
    fields[opensocial.Person.Field.THUMBNAIL_URL] = $("link[rel=thumbnail]", xml).attr("href");
  }
  if ($("link[rel=alternate]", xml)) {
    fields[opensocial.Person.Field.PROFILE_URL] = $("link[rel=alternate]", xml).attr("href");
  }
  person = new opensocial.Person(fields, isViewer, isOwner);

  dataResponseValues[requestName]
        = new opensocial.ResponseItem(request, person, globalError);

  callback(new opensocial.DataResponse(dataResponseValues, globalError));
};

/** callback for handling an ajax call to retrieve a list of friends */
opensocial.RailsContainer.prototype.onFetchPersons = function(xml, request, callback, requestName, isViewer, isOwner) {
  var globalError = false;
  var dataResponseValues = [];
  var persons = [];
  var entries = $(xml).find("entry");
  for (i = 0; i < entries.length; i++) {
      var fields = {
            'id' : $(entries[i]).find('id').text(),
            'name' : $(entries[i]).find('title').text()
      };
      var person = new opensocial.Person(fields, isViewer, isOwner);
      persons = persons.concat(person);
  }

  var requestedValue = new opensocial.Collection(persons);
  dataResponseValues[requestName]
        = new opensocial.ResponseItem(request, requestedValue, globalError);

  callback(new opensocial.DataResponse(dataResponseValues, globalError));
};

/**
 * This method returns the data requested about the viewer and his/her friends.
 * Since this is an in memory container, it is merely returning the member
 * variables. In a real world container, this would involve making an ajax
 * request to fetch the values from the server.
 *
 * To keep this simple (for now), the PeopleRequestFields values such as sort
 * order, filter, pagination, etc. specified in the DataRequest are ignored and
 * all requested data is returned in a single call back.
 *
 * @param {Object} dataRequest The object that specifies the data requested.
 * @param {Function} callback The callback method on completion.
 */
opensocial.RailsContainer.prototype.requestData = function(dataRequest,
    callback) {
  var requestObjects = dataRequest.getRequestObjects();
  var dataResponseValues = {};
  var globalError = false;

  for (var requestNum = 0; requestNum < requestObjects.length; requestNum++) {
    var request = requestObjects[requestNum].request;
    var requestName = requestObjects[requestNum].key;
    var requestedValue;
    var hadError = false;

    switch (request.type) {
      case 'FETCH_PERSON' :
        var personId = request.id;
        if (personId == opensocial.DataRequest.PersonId.VIEWER) {
          personId = "me"
        } else if (personId == opensocial.DataRequest.PersonId.OWNER) {
          //TODO - am I supposed to know who the OWNER of this page is?
        }
        // request "/feeds/people/me"
        $.get("/feeds/people/" + personId, function(data,textStatus) {
          opensocial.RailsContainer.prototype.onFetchPerson(data, request, callback, requestName, true, false);
        });
        // return because this is an asychronous call
        return;

      case 'FETCH_PEOPLE' :
        var idSpec = request.idSpec;
        var persons = [];
        if (idSpec == opensocial.DataRequest.Group.VIEWER_FRIENDS) {
          $.get("/feeds/people/me/friends", function(data,textStatus) {
            opensocial.RailsContainer.prototype.onFetchPersons(data, request, callback, requestName, true, false);
          });
          return;
          //persons = this.viewerFriends.asArray().concat();
        } else if (idSpec == opensocial.DataRequest.Group.OWNER_FRIENDS) {
          persons = this.ownerFriends.asArray().concat();
        } else {
          if (!opensocial.Container.isArray(idSpec)) {
            idSpec = [idSpec];
          }
          for (var i = 0; i < idSpec.length; i++) {
            var person = this.viewerFriends.getById(idSpec[i]);
            if (person == null) {
              person = this.ownerFriends.getById(idSpec[i]);
            }
            if (person != null) {
              persons.push(person);
            }
          }
        }
        requestedValue = new opensocial.Collection(persons);
        break;

      case 'FETCH_GLOBAL_APP_DATA' :
        var values = {};
        var keys =  request.keys;
        for (var i = 0; i < keys.length; i++) {
          values[keys[i]] = this.globalAppData[keys[i]];
        }
        requestedValue = values;
        break;

      case 'FETCH_INSTANCE_APP_DATA' :
        var values = {};
        var keys =  request.keys;
        for (var i = 0; i < keys.length; i++) {
          values[keys[i]] = this.instanceAppData[keys[i]];
        }
        requestedValue = values;
        break;

      case 'UPDATE_INSTANCE_APP_DATA' :
        this.instanceAppData[request.key] = request.value;
        break;

      case 'FETCH_PERSON_APP_DATA' :
        var ids = this.getIds(request.idSpec);

        var values = {};
        for (var i = 0; i < ids.length; i++) {
          var id = ids[i];
          if (this.personAppData[id]) {
            values[id] = {};
            for (var j = 0; j < request.keys.length; j++) {
              values[id][request.keys[j]]
                  = this.personAppData[id][request.keys[j]];
            }
          }
        }
        requestedValue = values;
        break;

      case 'UPDATE_PERSON_APP_DATA' :
        var userId = request.id;
        // Gadgets can only edit viewer data
        if (userId == opensocial.DataRequest.PersonId.VIEWER
            || userId == this.viewer.getId()) {
          userId = this.viewer.getId();
          this.personAppData[userId] = this.personAppData[userId] || {};
          this.personAppData[userId][request.key] = request.value;
        } else {
          hadError = true;
        }

        break;

      case 'FETCH_ACTIVITIES' :
        var ids = this.getIds(request.idSpec);

        var requestedActivities = [];
        for (var i = 0; i < ids.length; i++) {
          requestedActivities
              = requestedActivities.concat(this.activities[ids]);
        }
        requestedValue = {
          // Real containers should set the requested stream here
          'requestedStream' : null,
          'activities' : new opensocial.Collection(requestedActivities)};
        break;
    }

    dataResponseValues[requestName]
        = new opensocial.ResponseItem(request, requestedValue, hadError);
    globalError = globalError || hadError;

  }

  callback(new opensocial.DataResponse(dataResponseValues, globalError));
};

